<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <title>Bug 卡片墙</title>
    <link rel="icon"
        href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🐝</text></svg>">
    <style>
        :root {
            --bg: #f7f8fa;
            --card: #fff;
            --primary: #6366f1;
            --done: #10b981;
            --undone: #ef4444;
            --text: #111;
            --sub: #555;
            --line: #e5e7eb;
        }

        * {
            box-sizing: border-box;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif
        }

        body {
            margin: 0;
            background: var(--bg);
            color: var(--text)
        }

        header {
            padding: 12px 24px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            border-bottom: 1px solid var(--line)
        }

        #datePicker {
            cursor: pointer;
            font-weight: 600;
            font-size: 17px
        }

        #doneCount {
            font-size: 15px;
            color: var(--done);
            margin-left: 6px
        }

        #addBtn,
        #previewBtn {
            padding: 4px 12px;
            border: none;
            border-radius: 16px;
            background: var(--primary);
            color: #fff;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 4px;
            transition: .2s
        }

        #addBtn:hover,
        #previewBtn:hover {
            background: #4f46e5
        }

        #addBtn::before {
            content: '＋';
            font-size: 16px;
            line-height: 1
        }

        #previewBtn::before {
            content: '👁';
            font-size: 16px
        }

        main {
            max-width: 960px;
            margin: 24px auto;
            padding: 0 20px;
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
            gap: 20px
        }

        .card {
            background: var(--card);
            border-radius: 8px;
            padding: 16px;
            border: 1px solid var(--line);
            border-left: 3px solid var(--undone);
            transition: .2s;
            box-shadow: 0 1px 3px rgba(0, 0, 0, .05);
            position: relative
        }

        .card:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0, 0, 0, .06)
        }

        .card.done {
            border-left: 3px solid var(--done);
            opacity: .6
        }

        .check {
            float: right;
            margin-left: 8px;
            accent-color: var(--done)
        }

        .card textarea {
            width: 100%;
            min-height: 60px;
            border: none;
            resize: vertical;
            font-size: 14px;
            color: var(--text);
            outline: none;
            line-height: 1.4
        }

        .empty-tip {
            text-align: center;
            color: var(--sub);
            padding: 60px 0
        }

        /* ===== 日期弹窗（美化版） ===== */
        #history {
            display: none;
            position: fixed;
            inset: 0;
            background: rgba(0, 0, 0, .4);
            z-index: 300;
            align-items: center;
            justify-content: center;
            animation: fadeIn .2s ease;
        }

        #history>div {
            background: #fff;
            border-radius: 12px;
            padding: 24px;
            min-width: 260px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, .12);
            animation: scaleIn .2s ease;
        }

        #history input {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid var(--line);
            border-radius: 8px;
            font-size: 15px;
        }

        #history button {
            margin-top: 12px;
            width: 100%;
            padding: 8px;
            background: var(--primary);
            color: #fff;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 15px;
        }

        @keyframes fadeIn {
            from {
                opacity: 0
            }

            to {
                opacity: 1
            }
        }

        @keyframes scaleIn {
            from {
                transform: scale(.9)
            }

            to {
                transform: scale(1)
            }
        }

        /* ===== 预览弹窗 ===== */
        #previewModal {
            display: none;
            position: fixed;
            inset: 0;
            background: rgba(0, 0, 0, .4);
            z-index: 300;
            align-items: center;
            justify-content: center;
            animation: fadeIn .2s ease;
        }

        #previewModal>div {
            background: #fff;
            border-radius: 12px;
            padding: 24px;
            max-width: 480px;
            width: 100%;
            white-space: pre-wrap;
            font-size: 15px;
            line-height: 1.6;
            box-shadow: 0 8px 32px rgba(0, 0, 0, .12);
            animation: scaleIn .2s ease;
        }

        .btn-row {
            display: flex;
            gap: 8px;
            margin-top: 12px
        }

        .btn-row button {
            flex: 1;
            padding: 8px;
            border: none;
            border-radius: 8px;
            background: var(--primary);
            color: #fff;
            font-size: 15px;
            cursor: pointer
        }

        .btn-row button:hover {
            background: #4f46e5
        }

        #ctxMenu {
            display: none;
            position: absolute;
            background: #fff;
            border: 1px solid var(--line);
            border-radius: 6px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
            z-index: 999;
            padding: 4px 0;
            font-size: 14px
        }

        #ctxMenu button {
            width: 100%;
            border: none;
            background: none;
            padding: 6px 12px;
            text-align: left;
            cursor: pointer;
            font-size: 14px;
            color: var(--text)
        }

        #ctxMenu button:hover {
            background: #f3f4f6
        }
    </style>
</head>

<body>
    <header>
        <span id="datePicker" title="点击查看历史"></span>
        <span id="doneCount">0 ✓</span>
        <div style="display:flex;gap:8px">
            <button id="previewBtn" title="当日总览">预览</button>
            <button id="addBtn" title="新增卡片（Alt+N / Alt+Enter）">新增</button>
        </div>
    </header>

    <main id="board"></main>

    <!-- 日期选择（美化弹窗） -->
    <div id="history">
        <div>
            <input type="date" id="dateSel">
            <button id="goBtn">前往</button>
        </div>
    </div>

    <!-- 一键预览弹窗 -->
    <div id="previewModal">
        <div>
            <div id="previewContent"></div>
            <div class="btn-row">
                <button id="copyBtn">一键复制</button>
                <button id="closePreview">关闭</button>
            </div>
        </div>
    </div>

    <!-- 右键菜单 -->
    <div id="ctxMenu">
        <button data-action="delete">删除卡片</button>
    </div>

    <script>
        /* ===== 工具 ===== */
        const fmt = d => d.toISOString().slice(0, 10);
        function key(date) { return `bugs_${date}`; }
        const getData = date => JSON.parse(localStorage.getItem(key(date)) || '[]')
            .map(i => typeof i === 'string' ? { text: i, done: false } : i);
        const saveData = (date, arr) => localStorage.setItem(key(date), JSON.stringify(arr));

        let currentDate = fmt(new Date());

        /* ===== DOM ===== */
        const datePicker = document.getElementById('datePicker');
        const doneCnt = document.getElementById('doneCount');
        const addBtn = document.getElementById('addBtn');
        const previewBtn = document.getElementById('previewBtn');
        const board = document.getElementById('board');
        const historyDlg = document.getElementById('history');
        const dateSel = document.getElementById('dateSel');
        const goBtn = document.getElementById('goBtn');
        const previewModal = document.getElementById('previewModal');
        const previewContent = document.getElementById('previewContent');
        const closePreview = document.getElementById('closePreview');
        const copyBtn = document.getElementById('copyBtn');
        const ctxMenu = document.getElementById('ctxMenu');

        /* ===== 渲染 ===== */
        function render(date) {
            const data = getData(date).sort((a, b) => a.done - b.done);
            board.innerHTML = '';
            doneCnt.textContent = data.filter(b => b.done).length;
            datePicker.textContent = new Date(date + 'T00:00:00').toLocaleDateString('zh-CN', { month: 'long', day: 'numeric' });

            if (data.length === 0) {
                const tip = document.createElement('div');
                tip.className = 'empty-tip';
                tip.textContent = date === fmt(new Date()) ? '今天还没有 Bug，真棒！' : '当日无记录';
                board.appendChild(tip);
                return;
            }
            data.forEach((item, i) => {
                const card = document.createElement('div');
                card.className = 'card' + (item.done ? ' done' : '');
                card.innerHTML = `
            <input type="checkbox" class="check" ${item.done ? 'checked' : ''}>
            <textarea placeholder="请描述 Bug…">${item.text}</textarea>`;
                const ta = card.querySelector('textarea');
                const chk = card.querySelector('input');

                ta.addEventListener('input', () => {
                    const d = getData(date);
                    d[i].text = ta.value.trim();
                    saveData(date, d);
                    if (date === fmt(new Date())) doneCnt.textContent = d.filter(b => b.done).length;
                });

                chk.addEventListener('change', () => {
                    const d = getData(date);
                    d[i].done = chk.checked;
                    saveData(date, d);
                    render(date);
                    if (date === fmt(new Date())) doneCnt.textContent = d.filter(b => b.done).length;
                });

                card.addEventListener('contextmenu', e => {
                    e.preventDefault();
                    ctxMenu.style.left = e.pageX + 'px';
                    ctxMenu.style.top = e.pageY + 'px';
                    ctxMenu.style.display = 'block';
                    ctxMenu.dataset.index = i;
                });
                board.appendChild(card);
            });
        }

        /* ===== 右键删除 ===== */
        document.addEventListener('click', () => ctxMenu.style.display = 'none');
        window.addEventListener('blur', () => ctxMenu.style.display = 'none');
        ctxMenu.querySelector('button[data-action="delete"]').addEventListener('click', () => {
            const idx = +ctxMenu.dataset.index;
            const d = getData(currentDate);
            d.splice(idx, 1);
            saveData(currentDate, d);
            render(currentDate);
            ctxMenu.style.display = 'none';
        });

        /* ===== 日期切换 ===== */
        datePicker.addEventListener('click', () => {
            dateSel.value = currentDate;
            historyDlg.style.display = 'flex';
        });
        goBtn.addEventListener('click', () => {
            currentDate = dateSel.value || fmt(new Date());
            historyDlg.style.display = 'none';
            render(currentDate);
        });
        historyDlg.addEventListener('click', e => { if (e.target === historyDlg) historyDlg.style.display = 'none'; });

        /* ===== 新增卡片 ===== */
        function addBug() {
            if (currentDate !== fmt(new Date())) { currentDate = fmt(new Date()); }
            const d = getData(currentDate);
            d.unshift({ text: '', done: false });
            saveData(currentDate, d);
            render(currentDate);
            board.querySelector('.card:first-child textarea')?.focus();
        }
        addBtn.addEventListener('click', addBug);

        /* ===== 一键预览 ===== */
        function showPreview() {
            const list = getData(currentDate);
            if (list.length === 0) {
                previewContent.textContent = '今日暂无 Bug！';
            } else {
                previewContent.textContent = list
                    .map((it, idx) => `${idx + 1}. ${it.text}(${it.done ? '已完成' : '未完成'})`)
                    .join('\n');
            }
            previewModal.style.display = 'flex';
        }
        previewBtn.addEventListener('click', showPreview);
        closePreview.addEventListener('click', () => previewModal.style.display = 'none');
        copyBtn.addEventListener('click', () => {
            navigator.clipboard.writeText(previewContent.textContent).then(() => {
                copyBtn.textContent = '已复制';
                setTimeout(() => copyBtn.textContent = '一键复制', 1200);
            });
        });
        previewModal.addEventListener('click', e => { if (e.target === previewModal) previewModal.style.display = 'none'; });

        /* ===== 快捷键 ===== */
        document.addEventListener('keydown', e => {
            if (e.altKey && (e.key.toLowerCase() === 'n' || e.key.toLowerCase() === 'enter')) {
                e.preventDefault();
                addBug();
            }
        });

        render(currentDate);
    </script>
</body>

</html>